import { Graph, Shape, Addon } from "@antv/x6";
// import registerNodes from "./nodes/registerNodes";
// import registerPortLayouts from "./portLayouts/registerPortLayouts";
import EventBus from "../../event-bus";
import BusEvents from "../../event-bus/event-types";

const { Dnd } = Addon;

export default class GraphEditor {
  graph = null;
  dnd = null;

  constructor(container, minimapContainer) {
    this.init(container, minimapContainer);
    this.initDnd(); // dnd 用来做拖拽处理的
    this.initRegister();
    this.initEvents();
  }

  /**
   * 初始化 graph
   */
  init(container, minimapContainer) {
    this.container = container;
    this.graph = new Graph({
      container: container,
      autoResize: true,
      // 绘制网格
      grid: {
        size: 5,
        visible: false,
        type: "doubleMesh",
        args: [
          {
            // color: "#eee", // 主网格线颜色
            color: "#a9a9a9",
            thickness: 1, // 主网格线宽度
          },
          {
            // color: "#ddd", // 次网格线颜色
            color: "#c0c0c0",
            thickness: 1, // 次网格线宽度
            factor: 5, // 主次网格线间隔
          },
        ],
      },
      // 背景
      background: {
        // color: "#ffffff",
        color: "rgba(128, 128, 128, 0.2)",
      },
      // 对齐线
      snapline: true,
      // 滚动画布
      scroller: {
        enabled: true,
        pannable: true,
      },
      // 小地图
      minimap: {
        enabled: true,
        container: minimapContainer,
        width: 160,
        height: 200,
      },
      // 撤销、重做
      history: true,
      // 剪切板
      clipboard: true,
      // 键盘快捷键
      keyboard: {
        enabled: true,
        global: true,
      },
      // 鼠标滚轮缩放
      mousewheel: {
        enabled: true,
        modifiers: ["ctrl"],
      },
      // 点选、框选
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        modifiers: ["alt"],
        movable: true,
      },
      // 旋转节点
      rotating: false,
      // 缩放节点
      resizing: {
        enabled: (node) => {
          let nodeClass;
          if (node.getData().type) {
            nodeClass = node.getData().type.split(".")[0];
          }
          if (nodeClass === "subsystem") {
            return true;
          }
          return false;
        },
      },
      // 平移节点
      translating: {
        restrict: false,
      },
      // 平移缩放节点的基础选项
      transforming: {
        clearAll: true,
        clearOnBlankMouseDown: true,
      },
      // 嵌套节点
      embedding: {
        enabled: false,
        // findParent: "bbox",
        // frontOnly: true,
      },
      // 连线选项
      connecting: {
        snap: {
          radius: 50,
        },
        allowBlank: false,
        allowMulti: "withPort",
        allowLoop: true,
        allowNode: false,
        allowEdge: false,
        allowPort: true,
        highlight: true,
        connector: "rounded",
        // connector: 'pai',
        connectionPoint: "boundary",
        router: {
          name: "manhattan",
          args: {
            step: 40,
            startDirections: ["right"],
            endDirections: ["left"],
          },
        },
        createEdge() {
          return new Shape.Edge({
            // router: {
            //   name: "er",
            //   args: {
            //     direction: "L",
            //     offset: "center",
            //   },
            // },
            router: {
              name: "manhattan",
              args: {
                step: 40,
                startDirections: ["right"],
                endDirections: ["left"],
              },
            },
            connector: { name: "rounded" },
            attrs: {
              line: {
                stroke: "#a0a0a0",
                strokeWidth: 2,
                targetMarker: {
                  name: "classic",
                  size: 7,
                },
              },
            },
          });
        },
        validateEdge: (args) => {
          const { edge } = args;
          return !!(edge && edge.target && edge.target.port);
        },
        validateMagnet({ magnet }) {
          return magnet.getAttribute("port-group") !== "in";
        },
        validateConnection({ targetView, targetMagnet }) {
          if (!targetMagnet) {
            return false;
          }
          if (targetMagnet.getAttribute("port-group") !== "in") {
            return false;
          }
          if (targetView) {
            const node = targetView.ceil;
            if (node) {
              const portId = targetMagnet.getAttribute("port");
              const usedInPorts = node.getUsedInPorts(this.graph);
              if (usedInPorts.find((port) => port && port.id === portId)) {
                return false;
              }
            }
          }
          return true;
        },
      },
      // 高亮选项
      highlighting: {
        magnetAvailable: {
          name: "stroke",
          args: {
            padding: 0,
            attrs: {
              "stroke-width": 0,
              // stroke: "red",
              fill: "rgba(0, 0, 0, 0.2)",
            },
          },
        },
        magnetAdsorbed: {
          name: "stroke",
          args: {
            attrs: {
              "stroke-width": 0,
              // fill: "#fff",
              // stroke: "#31d0c6",
            },
          },
        },
      },
      // port 的渲染
      onPortRendered(args) {
        const selectors = args.contentSelectors;
        const container = selectors && selectors.foContent;
        const port = args.port;
        if (container) {
          if (port.group === "in") {
            container.innerHTML = `
              <span class="html-port-in"><i class="el-icon-caret-right"></i><span class="html-port-name"> ${port.name}</span></span>
              `;
          } else {
            container.innerHTML = `
              <span class="html-port-out"><span class="html-port-name">${port.name} </span><i class="el-icon-caret-right"></i></span>
              `;
          }
        }
      },
    });
    // console.log(graph);
  }

  /**
   * 初始化 dnd
   */
  initDnd() {
    const { graph } = this;
    this.dnd = new Dnd({
      target: graph,
      animation: true,
      validateNode: validate,
      getDropNode: getDropNode,
    });

    function validate() {
      return true;
    }
    function getDropNode(node) {
      let nodeClone = node.clone();
      nodeClone.getData().id = nodeClone.id;
      EventBus.$emit(BusEvents.INTERACT_ADD_NODE, {
        id: nodeClone.id,
        name: nodeClone.getData().name,
      });
      return nodeClone;
    }
  }

  /**
   * 初始化 registerNodes 和 registerEdges
   */
  initRegister() {
    // registerNodes();
    // registerPortLayouts();
  }

  /**
   * 初始化 graph 相关的事件
   */
  initEvents() {
    const { graph } = this;

    /** 将 command 和 key 进行绑定 */
    this.bindKeys(graph);
    // 节点选择 selection:changed
    graph.on("selection:changed", (args) => {
      const { removed, selected } = args;

      // todo: 将所有的 selected 节点告知主界面，以方便 props-panel 使用

      selected.forEach((cell) => {
        if (cell.isNode()) {
          cell.data.selected = true;
        }
        // if (cell.isEdge()) {

        // }
      });
      removed.forEach((cell) => {
        if (cell.isNode()) {
          cell.data.selected = false;
        }
      });
    });
    /** 节点相关的事件 */
    graph.on("node:dblclick", ({ node }) => {
      EventBus.$emit(BusEvents.INTERACT_DOUBLE_CLICK_NODE, { node });
    });
    graph.on("node:contextmenu", ({ e, node }) => {
      this.graph.select(node);
      const x = e.pageX,
        y = e.pageY;
      EventBus.$emit(BusEvents.INTERACT_RIGHT_CLICK_NODE, { x, y, node });
    });
  }

  /**
   * 对 graph 绑定一些 Key 事件
   */
  bindKeys(graph) {
    graph.bindKey("ctrl+z", () => {
      EventBus.$emit(BusEvents.COMMAND_UNDO);
    });
    graph.bindKey("ctrl+shift+z", () => {
      EventBus.$emit(BusEvents.COMMAND_REDO);
    });
    graph.bindKey("ctrl+c", () => {
      EventBus.$emit(BusEvents.COMMAND_COPY);
    });
    graph.bindKey("ctrl+v", () => {
      EventBus.$emit(BusEvents.COMMAND_PASTE);
    });
    graph.bindKey("ctrl+x", () => {
      EventBus.$emit(BusEvents.COMMAND_CUT);
    });
    graph.bindKey("delete", () => {
      EventBus.$emit(BusEvents.COMMAND_DELETE);
    });
    graph.bindKey("ctrl+s", () => {
      EventBus.$emit(BusEvents.COMMAND_SAVE);
    });
    graph.bindKey("esc", () => {
      EventBus.$emit(BusEvents.COMMAND_CHANGE_MODE);
    });
    graph.bindKey("up", (e) => {
      e.preventDefault();
      EventBus.$emit(BusEvents.INTERACT_MOVE_UP);
    });
    graph.bindKey("right", (e) => {
      e.preventDefault();
      EventBus.$emit(BusEvents.INTERACT_MOVE_RIGHT);
    });
    graph.bindKey("down", (e) => {
      e.preventDefault();
      EventBus.$emit(BusEvents.INTERACT_MOVE_DOWN);
    });
    graph.bindKey("left", (e) => {
      e.preventDefault();
      EventBus.$emit(BusEvents.INTERACT_MOVE_LEFT);
    });
  }
}
